package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private VodConstantProperties vodConstantProperties;
    @Autowired
    private VodService vodService;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {

        return vodService.getVodMediaMap(file);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        //代理
        TrackInfoServiceImpl proxy = (TrackInfoServiceImpl) AopContext.currentProxy();

        Long userId = AuthContextHolder.getUserId();

        //保存声音基本信息
        TrackInfo trackInfo = new TrackInfo();
        // 1.1 声音基本属性通过拷贝赋值
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 1.2 声音的其它属性手动赋值
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        trackInfo.setUserId(userId);
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId())
                .orderByDesc(TrackInfo::getOrderNum)
                .last("limit 1");
        TrackInfo maxOrderNumTrackInfo = trackInfoMapper.selectOne(queryWrapper);
        Integer orderNum = maxOrderNumTrackInfo == null ? 1 : maxOrderNumTrackInfo.getOrderNum() + 1;
        trackInfo.setOrderNum(orderNum);  // 序列号

        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        if (trackMediaInfoVo != null) {
            trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaFileId(trackInfo.getMediaFileId());
        }
        trackInfoMapper.insert(trackInfo);
        //保存声音统计信息
        proxy.initTrackStat(trackInfo.getId());
        //修改声音对应的专辑包含声音的集数
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo != null) {
            albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        }
        albumInfoMapper.updateById(albumInfo);
    }

    @Override
    public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    @Override
    public TrackInfo getTrackInfo(Long trackId) {
        return trackInfoMapper.selectById(trackId);
    }

    @Override
    public void updateTrackInfo(TrackInfoVo trackInfoVo, Long trackId) {
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (null == trackInfo) {
            throw new GuiguException(201, "声音不存在");
        }

        String oldmediaFileId = trackInfo.getMediaFileId();
        String newmediaFileId = trackInfoVo.getMediaFileId();

        //新数据替换旧数据
        BeanUtils.copyProperties(trackInfoVo, trackInfo);

        if (!StringUtils.isEmpty(newmediaFileId) && !oldmediaFileId.equals(newmediaFileId)) {
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(newmediaFileId);
            if (mediaInfo != null) {
                trackInfo.setMediaDuration(new BigDecimal(mediaInfo.getDuration()));
                trackInfo.setMediaType(mediaInfo.getType());
                trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
                trackInfo.setMediaSize(mediaInfo.getSize());
                trackInfo.setMediaFileId(newmediaFileId);
            }
            trackInfoMapper.updateById(trackInfo);
        }
    }

    @Override
    public void removeTrackInfo(Long trackId) {
        //1.修改专辑中的声音集数
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (null == trackInfo) {
            throw new GuiguException(201, "声音不存在");
        }
        Long albumId = trackInfo.getAlbumId();

        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (null == albumInfo) {
            throw new GuiguException(201, "声音对应的专辑不存在");
        }

        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);
        //2.删除声音基本信息
        trackInfoMapper.deleteById(trackId);

        //3.删除声音的统计信息
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));

        //4.删除vod中的声音信息
        vodService.removeVodInfo(trackInfo.getMediaFileId());
    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Long albumId, IPage<AlbumTrackListVo> albumTrackListVoPage) {
        IPage<AlbumTrackListVo> result = new Page<>();


        //1.根据专辑id获取专辑下声音信息
        IPage<AlbumTrackListVo> albumTrackListDb = trackInfoMapper.findAlbumTrackPage(albumTrackListVoPage, albumId);
        // 2.处理声音列表中每一个声音的isShowPaidMark（true/false）
        //2.1根据专辑id获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Assert.notNull(albumInfo, "该专辑不存在");
        // 2.2 获取专辑的付费类型(0101-免费、0102-vip免费、0103-付费)
        String payType = albumInfo.getPayType();
        // 2.3 获取专辑的价格类型(0201-单集 0202-整专辑)
        String priceType = albumInfo.getPriceType();
        // 2.4 获取专辑的免费声音集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        // 2.5 获取用户id(登录用户的id)
        Long userId = AuthContextHolder.getUserId();

        // 2.6 根据专辑的付费类型，判断如何返回声音列表数据
        switch (payType) {
            case "0101":
                // 2.6.1 整个专辑都是免费（所有声音都不用显示付费图标）
                result = albumTrackListDb;
                break;
            case "0102":
                // 2.6.2 专辑对vip是免费的。（处理付费图标的展示）
                result = dealPayTypeVip(priceType, tracksForFree, albumTrackListDb, userId, albumId);
                break;
            case "0103":
                // 2.6.3 专辑是付费的。（处理付费图标的展示）
                result = dealPayTypeNeedPaid(priceType, tracksForFree, albumTrackListDb, userId, albumId);
                break;
        }
        // 3.返回声音列表（处理完付费图标）
        return result;
    }

    //todo 查询声音统计维度
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackStatMapper.getTrackStatVo(trackId);
    }


    /*
     * @description: TODO 分集展示要购买的声音列表
     * @author: yyj
     * @date: 2025-02-10
     */
    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long currentTrackId) {
        //todo 展示当前集数之后的集数声音
        List<Map<String, Object>> result = new ArrayList<>();

        //1.获取用户对象
        Long userId = AuthContextHolder.getUserId();
        //2.获取声音对象
        TrackInfo trackInfo = trackInfoMapper.selectById(currentTrackId);
        if (null == trackInfo) {
            throw new GuiguException(201, "购买的声音不存在");
        }
        //3.获取专辑id
        Long albumId = trackInfo.getAlbumId();
        //4.获取专辑对象
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "购买的声音对应的专辑不存在");
        }

        //5.获取声音价格
        BigDecimal price = albumInfo.getPrice();
        //6.获取声音序列号
        Integer orderNum = trackInfo.getOrderNum();

        //7.当前声音后的所有声音
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TrackInfo::getAlbumId, albumId)
                .gt(TrackInfo::getOrderNum, orderNum)
                .orderByAsc(TrackInfo::getOrderNum)
                .last("limit 50");
        List<TrackInfo> trackInfos = trackInfoMapper.selectList(queryWrapper);

        // 9.查询当前用户已经购买当前专辑的声音id查询出来
        Result<Map<Long, String>> userPaidAlbumTrackList = userInfoFeignClient.getUserPaidAlbumTrackList(userId, albumId);
        Map<Long, String> userPaidAlbumTrackListDataMap = userPaidAlbumTrackList.getData();
        Assert.notNull(userPaidAlbumTrackListDataMap, "远程查询用户购买的当前专辑下的声音调用失败");

        //10.过滤已经购买的声音
        List<Long> reallyCanShowTrackLists = trackInfos.stream().map(TrackInfo::getId).filter(trackId -> StringUtils.isEmpty(userPaidAlbumTrackListDataMap.get(trackId))).collect(Collectors.toList());
        // 11.在展示购买的声音列表
        // 11.1 要展示的声音集数
        int size = reallyCanShowTrackLists.size();
        // 20集声音：3块（本集、后10集、后20集）
        // 23集声音：4块（本集、后10集、后20集 后23集）
        // 展示本集
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "本集"); // 名字展示
        map.put("price", price);// 本集的价格展示
        map.put("trackCount", 0);// 集数不展示（买本集还是其他集最区分）
        result.add(map);
        // 11.2 获取要展示的块数
        int block = size % 10 == 0 ? size / 10 : size / 10 + 1;
        for (int i = 1; i <= block; i++) {
            int count = i * 10;
            if (count >= size) {
                HashMap<String, Object> map1 = new HashMap<>();
                map1.put("name", "后" + size + "集"); // 名字展示
                map1.put("price", price.multiply(new BigDecimal(size)));// 本集的价格展示
                map1.put("trackCount", size);// 集数不展示（买本集还是其他集最区分）
                result.add(map1);
            }
            HashMap<String, Object> map2 = new HashMap<>();
            map2.put("name", "后" + count + "集"); // 名字展示
            map2.put("price", price.multiply(new BigDecimal(count)));// 本集的价格展示
            map2.put("trackCount", count);// 集数不展示（买本集还是其他集最区分）
            result.add(map2);
        }
        return result;
    }


    /*
     * @description: TODO 既能把买过的声音查询出来又能把买过的声音过滤掉 返回真正能买的声音
     * @author: yyj
     * @date: 2025-02-10
     */
    @Override
    public Result getPaidTrackAndFilterCanPayTrack(Long userId, Long albumId, Integer trackCount, Long trackId) {
        List<TrackInfo> result = new ArrayList<>();
        // 1.查询当前用户买过的专辑下的声音
        Result<Map<Long, String>> userPaidAlbumTrackList = userInfoFeignClient.getUserPaidAlbumTrackList(userId, albumId);
        Map<Long, String> userPaidAlbumTrackListData = userPaidAlbumTrackList.getData();
        Assert.notNull(userPaidAlbumTrackListData, "远程查询用户微服务获取购买的声音信息失败");
        // 2.查询要买的声音
        //2.1购买本集
        // 2.查询要买的声音
        //2.1购买本集
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackCount == 0) {
            result.add(trackInfo);
        } else {
            LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TrackInfo::getAlbumId, albumId)
                    .gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                    .last("limit " + trackCount)
                    .orderByAsc(TrackInfo::getOrderNum);
            result = trackInfoMapper.selectList(queryWrapper);
        }
        //过滤(将已经买过的返回给order再到前端
        ArrayList<Long> longs = new ArrayList<>();
        for (TrackInfo trackInfo1 : result) {
            if(!StringUtils.isEmpty(userPaidAlbumTrackListData.get(trackInfo1.getId()))){
                longs.add(trackInfo1.getId());
                return Result.build(longs, 400, "已经存在");

            }
        }
        return Result.ok(result);
    }


    private IPage<AlbumTrackListVo> dealPayTypeVip(String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListDb, Long userId, Long albumId) {
        // 1.判断用户id是否存在
        // 1.1 用户不存在（直接返回免费声音列表）
        if (userId == null) {
            // 用户没登录，直接访问该接口
            // 策略一：一集声音都不让他看，直接抛出异常
            // 策略二：让他看免费的声音。把免费的级数声音返回给他去看
            List<AlbumTrackListVo> collect = albumTrackListDb.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= tracksForFree).collect(Collectors.toList());
            return albumTrackListDb.setRecords(collect);
        }
        // 1.2 用户存在
        // 1.2.1 根据用户id获取用户对象
        Result<UserInfoVo> userInfoResult = userInfoFeignClient.getUserInfo(userId);
        UserInfoVo data = userInfoResult.getData();
        Assert.notNull(data, "用户不存在");
        // 1.2.2 获取用户身份信息（是否是vip）
        Integer isVip = data.getIsVip();
        Date vipExpireTime = data.getVipExpireTime();
        // a)不是vip（把免费集数之外且还没买过的的都显示付费）
        if ("0".equals(isVip + "") || "1".equals(isVip + "") && vipExpireTime.before(new Date())) {
            return getReallyShowTrackListVoIPage(priceType, tracksForFree, albumTrackListDb, userId, albumId);
        } else {
            // b)是vip 一定没过期
            return albumTrackListDb;
        }
    }

    /**
     * 处理付费类型是付费
     */
    private IPage<AlbumTrackListVo> dealPayTypeNeedPaid(String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListDb, Long userId, Long albumId) {
        // 用户是否登录
        if (userId == null) {
            List<AlbumTrackListVo> freeAlbumTrackListVo = albumTrackListDb.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= tracksForFree).collect(Collectors.toList());
            return albumTrackListDb.setRecords(freeAlbumTrackListVo);
        }

        return getReallyShowTrackListVoIPage(priceType, tracksForFree, albumTrackListDb, userId, albumId);
    }


    private IPage<AlbumTrackListVo> getReallyShowTrackListVoIPage(String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListDb, Long userId, Long albumId) {
        // 1.判断单集
        if ("0201".equals(priceType)) {
            Result<Map<Long, String>> userIsPaidAlbumTrackListResult = userInfoFeignClient.getUserPaidAlbumTrackList(userId, albumId);
            Map<Long, String> data = userIsPaidAlbumTrackListResult.getData();
            if (data == null) {
                throw new GuiguException(201, "远程调用用户微服务获取用户购买的专辑下的声音列表失败");
            }
            //过滤
            List<AlbumTrackListVo> realShowTrackList = albumTrackListDb.getRecords().stream().map(albumTrackListVo -> {
                if (StringUtils.isEmpty(data.get(albumTrackListVo.getTrackId())) && albumTrackListVo.getOrderNum() > tracksForFree) {
                    //meiyoumaiguo
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            return albumTrackListDb.setRecords(realShowTrackList);
        } else {
            // 2.判断整专辑
            // 2.1 获取用户买过的专辑
            Result<Boolean> userIsPaidAlbumResult = userInfoFeignClient.getUserPaidAlbum(userId, albumId);
            Boolean isPaidAlbum = userIsPaidAlbumResult.getData();
            if (null == isPaidAlbum) {
                throw new GuiguException(201, "远程调用用户微服务获取用户购买的专辑失败");
            }
            // 2.2 过滤以及处理
            // 如果这个专辑买过（直接返回）
            if (isPaidAlbum) {
                return albumTrackListDb;
            }
            // 如果这个专辑没有买过(只需判断这个专辑下的声音是否在免费集数中 如果在免费中 直接返回 如果不在 修改付费图标)
            List<AlbumTrackListVo> realShowTrackList = albumTrackListDb.getRecords().stream().map(albumTrackListVo -> {
                if (albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            return albumTrackListDb.setRecords(realShowTrackList);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void initTrackStat(Long trackId) {
        ArrayList<String> trackStatTypes = new ArrayList<>();
        trackStatTypes.add(SystemConstant.ALBUM_STAT_PLAY);
        trackStatTypes.add(SystemConstant.ALBUM_STAT_SUBSCRIBE);
        trackStatTypes.add(SystemConstant.ALBUM_STAT_BROWSE);
        trackStatTypes.add(SystemConstant.ALBUM_STAT_COMMENT);
        for (String trackStatType : trackStatTypes) {
            TrackStat trackStat = new TrackStat();
            trackStat.setTrackId(trackId);
            trackStat.setStatType(trackStatType);
            trackStat.setStatNum(0);
            trackStatMapper.insert(trackStat);
        }
    }

}
